package com.vortex.cloud.zhsw.xinyang.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.vortex.cloud.zhsw.xinyang.dto.BaseDTO;
import com.vortex.cloud.sdk.api.dto.jcss.reborn.FacilityDTO;
import com.vortex.cloud.zhsw.xinyang.support.Constants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;

import java.lang.reflect.Field;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

@Slf4j
public class FacilityTransferUtils {

    private static final String CATEGORY = "category";
    private static final String CATEGORY_NAME = "categoryName";
    private static final String LOCATION = "location";
    private static final String GEO_DTO = "GeometryInfoDTO";
    private static final Map<Class<?>, Field[]> DEFAULT_TYPE_VALUES;

    static {
        Set<Class<?>> subClass = ClassUtil.scanPackageBySuper("com.vortex.cloud.zhsw.jcss.dto.response", BaseDTO.class);
        Map<Class<?>, Field[]> values = Maps.newHashMap();
        for (Class<?> aClass : subClass) {
            values.put(aClass, aClass.getDeclaredFields());
        }
        DEFAULT_TYPE_VALUES = Collections.unmodifiableMap(values);
    }

    public static <T> void transDTO(T t, FacilityDTO dto) {
        if (ObjectUtil.isEmpty(t) || ObjectUtil.isEmpty(dto)) {
            return;
        }
        BeanUtils.copyProperties(dto, t);
        Field[] fields = DEFAULT_TYPE_VALUES.get(t.getClass());
        if (ObjectUtil.isEmpty(fields) || fields.length == Constants.Figure.ZERO) {
            fields = t.getClass().getDeclaredFields();
        }
        for (Field field : fields) {
            String fieldName = field.getName();
            Object newValue;
            // 有设施类型字段单独处理
            boolean hasCategory = StrUtil.isNotEmpty(dto.getFacilityClassId()) && fieldName.contains(CATEGORY);
            if (hasCategory) {
                if (fieldName.equals(CATEGORY)) {
                    setFieldValue(t, field, dto.getFacilityClassCode());
                }
                if (fieldName.equals(CATEGORY_NAME)) {
                    setFieldValue(t, field, dto.getFacilityClassName());
                }
                continue;
            }
            // geometry对象单独处理
            boolean hasGeo = ObjectUtil.isNotEmpty(dto.getGeometryInfo()) && field.getType().getName().contains(GEO_DTO) && fieldName.equals(LOCATION);
            if (hasGeo) {
                setFieldValue(t, field, dto.getGeometryInfo());
                continue;
            }
            // dataJson 数据单独处理
            if (CollUtil.isNotEmpty(dto.getDataJson())) {
                Map<String, Object> dataMap = dto.getDataJson();
                if (!dataMap.containsKey(fieldName) && !dataMap.containsKey(fieldName + "Id")) {
                    continue;
                }
                newValue = ObjectUtil.isEmpty(dataMap.get(fieldName)) ? dataMap.get(fieldName + "Id") :
                        dataMap.get(fieldName);
                setFieldValue(t, field, newValue);
            }
        }
    }

    public static List<?> transDTO(Class<?> clazz, List<FacilityDTO> dtoList) {
        if (CollUtil.isEmpty(dtoList)) {
            return null;
        }
        List<Object> list = Lists.newArrayList();
        for (FacilityDTO dto : dtoList) {
            Object newInstance = null;
            try {
                newInstance = clazz.getConstructor().newInstance();
            } catch (Exception e) {
                log.error("构造对象失败", e);
            }
            transDTO(newInstance, dto);
            list.add(newInstance);
        }
        return list;
    }

    private static <T> void setFieldValue(T t, Field field, Object newValue) {
        if (ObjectUtil.isNotEmpty(newValue)) {
            field.setAccessible(true);
            assert newValue != null;
            try {
                if (field.getType().equals(Integer.class)) {
                    field.set(t, Integer.valueOf(newValue.toString()));
                } else if (field.getType().equals(Double.class)) {
                    field.set(t, Double.valueOf(newValue.toString()));
                } else {
                    field.set(t, newValue);
                }
            } catch (IllegalAccessException e) {
                log.error("反射赋值失败", e);
            }
        }
    }
}
